package com.tianji.promotion.utils;

import com.tianji.common.exceptions.BizIllegalException;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

@Component
@Aspect  //Aop切面注解
@RequiredArgsConstructor
public class MyLockAspect implements Ordered {
    private final RedissonClient redissonClient;
    private final MyLockFactory lockFactory;

    @Around("@annotation(myLock)")
    public Object tryLock(ProceedingJoinPoint pjp ,MyLock myLock) throws Throwable {

        //1.创建锁对象 根据不同类型获得不同锁对象
//        RLock lock = redissonClient.getLock(myLock.name());
        RLock lock = lockFactory.getLock(myLock.lockType(), myLock.name());
        //2.尝试获得锁
        boolean result = lock.tryLock(myLock.waitTime(), myLock.leaseTime(), myLock.unit());
        //3.获得锁失败
        if (!result){
            throw new BizIllegalException("请求太频繁");
        }
        try {
            //4.获得锁成功
            return pjp.proceed();
        } finally {
            //5.释放锁
            lock.unlock();
        }
    }

    /*增加权重  让锁先执行然后事务再执行 数值越小越先执行
    *
    *
    * Spring中的AOP切面有很多，会按照Order排序，按照Order值从小到大依次执行。
    * Spring事务AOP的order值是Integer.MAX_VALUE，优先级最低。
    *
    * 我们的分布式锁一定要先于事务执行，因此，我们的切面一定要实现Ordered接口，
    * 指定order值小于Integer.MAX_VALUE即可。
    *
    * */
    @Override
    public int getOrder() {
        return 0;
    }
}
